from enum import IntEnum, auto


class OpCode(IntEnum):
    # 从只读区域读取值到栈顶，值的offset在下一个字节中
    CONSTANT = auto()
    # 将Nil压入栈顶
    NIL = auto()
    # 将True压入栈顶
    TRUE = auto()
    # 将False压入栈顶
    FALSE = auto()
    # 弹出栈顶元素
    POP = auto()
    # 将局部变量读取到栈顶，offset在下一个字节中
    GET_LOCAL = auto()
    # 将局部变量设置为栈顶的值，offset在下一个字节中
    SET_LOCAL = auto()
    # 读取全局变量到栈顶，变量名字符串的offset在下一个字节中
    GET_GLOBAL = auto()
    # 将栈顶元素定义为全局变量，变量名字符串的offset在下一个字节中
    DEFINE_GLOBAL = auto()
    # 将全局变量设置为栈顶元素的值，变量名字符串的offset在下一个字节中
    SET_GLOBAL = auto()
    # 读取upvalue值到栈顶，offset在下一个字节中
    GET_UPVALUE = auto()
    # 将upvalue设置为栈顶元素的值，offset在下一个字节中
    SET_UPVALUE = auto()
    # 读取自由变量（被在当前scope中定义的函数捕获的自由变量）到栈顶，offset在下一个字节中；需要将值进行拆包
    GET_FREE_VALUE = auto()
    # 将自由变量的值设置为栈顶元素，offset在下一个字节中
    SET_FREE_VALUE = auto()
    # 读取栈顶对象的属性值到栈顶，属性名字符串常量在下一个字节中
    GET_PROPERTY = auto()
    # | 对象 |
    # | 待设置的属性值 | <-- 栈顶
    # 设置对象的属性值，其中属性名字符串常量在下一个字节中
    SET_PROPERTY = auto()
    # todo
    GET_SUPER = auto()
    # 将栈顶元素变成逃逸变量，分配到堆上
    ESCAPE_VALUE = auto()
    # 弹出栈顶最上方两个元素，将bool(arg1 == arg2)压栈
    EQUAL = auto()
    # 弹出最上方的两个数值，若将bool(arg1 > arg2)压栈
    # | arg1 |
    # | arg2 | <-- 栈顶
    GREATER = auto()
    # 弹出栈顶最上方的两个数值，若将bool(arg1 < arg2)压栈
    # | arg1 |
    # | arg2 | <-- 栈顶
    LESS = auto()
    # 弹出栈顶最上方的两个元素，将它们的和压入栈顶
    ADD = auto()
    # 弹出栈顶最上方的两个数值，若将arg1 - arg2的值压栈
    # | arg1 |
    # | arg2 | <-- 栈顶
    SUBTRACT = auto()
    # 弹出栈顶最上方的两个数值，若将arg1 * arg2的值压栈
    # | arg1 |
    # | arg2 | <-- 栈顶
    MULTIPLY = auto()
    # 弹出栈顶最上方的两个数值，若将arg1 / arg2的值压栈
    # | arg1 |
    # | arg2 | <-- 栈顶
    DIVIDE = auto()
    # 弹出栈顶值，将!bool(arg)的值压栈
    # | arg | <-- 栈顶
    NOT = auto()
    # 弹出栈顶数值，将其取反后压栈
    NEGATE = auto()
    # 打印栈顶元素
    PRINT = auto()
    # 无条件跳转，有符号的偏移在后面2字节，大端字节序
    JUMP = auto()
    # 若栈顶元素为False，则跳转，有符号的偏移在后面2字节，大端字节序
    JUMP_IF_FALSE = auto()
    # 函数/方法调用，调用前的栈布局如下
    # | 闭包对象（） |
    # | 参数1 |
    # | ...  |
    # | 参数N |
    # 参数个数在下一个字节中
    CALL = auto()
    # todo
    SUPER_INVOKE = auto()
    # 生成闭包对象，压入栈顶
    # 捕捉到的自由变量在后续的字节中，具体见代码
    CLOSURE = auto()
    # 退出当前调用栈帧，栈顶元素为返回值
    RETURN = auto()
    # 生成类对象
    CLASS = auto()
    # 调用时栈布局
    # | child class object |
    # | super class object | <-- 栈顶
    # 将super class的方法复制到child class中
    INHERIT = auto()
    # 调用时栈布局
    # | class object |
    # | method closure | <-- 栈顶
    # 将栈顶的方法闭包加入class object
    METHOD = auto()
